home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / Winter Shell 1.0d2 / Source / Libraries / OffscreenLib / OffscreenLib.c next >
Encoding:
C/C++ Source or Header  |  1994-01-11  |  8.7 KB  |  293 lines  |  [TEXT/KAHL]

  1. /* Black and white offscreen bitmaps.
  2.     94/01/11 aih removed requirement that port can't be a color port
  3.     94/01/02 aih added draw call-back field
  4.     93/12/20 aih added bounds field
  5.     93/12/05 aih created */
  6.  
  7. #include <limits.h>
  8. #include "OffscreenLib.h"
  9. #include "MemoryLib.h"
  10. #include "RectangleLib.h"
  11.  
  12. /* true if a valid offscreen handle */
  13. Boolean OffscreenValid(OffscreenHandle offscreen)
  14. {
  15.     if (! HandleValidSize(offscreen, sizeof(OffscreenType))) return(false);
  16.     if (! (**offscreen).draw) return(false);
  17.     if (! (**offscreen).base) return(false);
  18.     if (*(**offscreen).base && ! HandleValid((**offscreen).base)) return(false);
  19.     return(true);
  20. }
  21.  
  22. /* create a new offscreen bitmap */
  23. OffscreenHandle OffscreenBegin(GrafPtr port, OffscreenDrawType draw, void *data)
  24. {
  25.     volatile OffscreenHandle offscreen = NULL;
  26.     void *tmp = NULL;
  27.     
  28.     require(port != NULL);
  29.     require(draw != NULL);
  30.     TRY {
  31.         offscreen = HandleBeginClear(sizeof(OffscreenType));
  32.         (**offscreen).port = port;
  33.         tmp = HandleBegin(0); EmptyHandle(tmp); HPurge(tmp);
  34.         (**offscreen).base = tmp;
  35.         (**offscreen).draw = draw;
  36.         (**offscreen).data = data;
  37.         (**offscreen).bounds = port->portRect;
  38.         tmp = NewRgn(); FailNIL(tmp); (**offscreen).mask = tmp;
  39.         tmp = NewRgn(); FailNIL(tmp); (**offscreen).clip = tmp;
  40.         tmp = NewRgn(); FailNIL(tmp); (**offscreen).vis = tmp;
  41.     } CATCH {
  42.         OffscreenEnd(offscreen);
  43.     } ENDTRY;
  44.     ensure(OffscreenValid(offscreen));
  45.     ensure(OffscreenPurged(offscreen));
  46.     return(offscreen);
  47. }
  48.  
  49. /* dispose of the offscreen bitmap */
  50. void OffscreenEnd(OffscreenHandle offscreen)
  51. {
  52.     if (offscreen) {
  53.         require(! (**offscreen).drawing);
  54.         if ((**offscreen).mask) DisposeRgn((**offscreen).mask);
  55.         if ((**offscreen).clip) DisposeRgn((**offscreen).clip);
  56.         if ((**offscreen).vis) DisposeRgn((**offscreen).vis);
  57.         if ((**offscreen).base) DisposeHandle((**offscreen).base);
  58.         HandleEnd(offscreen);
  59.     }
  60. }
  61.  
  62. /* return the bounding rectangle of the offscreen bitmap */
  63. void OffscreenBounds(OffscreenHandle offscreen, Rect *bounds)
  64. {
  65.     require(OffscreenValid(offscreen));
  66.     *bounds = (**offscreen).bounds;
  67.     ensure(RectValid(bounds));
  68. }
  69.  
  70. /* set the bounding rectangle of the offscreen bitmap; this can be any portion
  71.     of the offscreen bitmap's port */
  72. void OffscreenBoundsSet(OffscreenHandle offscreen, const Rect *bounds)
  73. {
  74.     require(OffscreenValid(offscreen));
  75.     require(RectValid(bounds));
  76.     (**offscreen).bounds = *bounds;
  77.     if (! OffscreenPurged(offscreen))
  78.         OffscreenPurge(offscreen);
  79.     ensure(OffscreenPurged(offscreen));
  80. }
  81.  
  82. /* set flag indicating that the offscreen bitmap must be reimaged */
  83. void OffscreenChange(OffscreenHandle offscreen)
  84. {
  85.     require(OffscreenValid(offscreen));
  86.     (**offscreen).changed = true;
  87. }
  88.  
  89. /* purge the offscreen bitmap */
  90. void OffscreenPurge(OffscreenHandle offscreen)
  91. {
  92.     require(OffscreenValid(offscreen));
  93.     require(! (**offscreen).srcbits.baseAddr);
  94.     EmptyHandle((**offscreen).base);
  95.     ensure(OffscreenPurged(offscreen));
  96. }
  97.  
  98. /* true if the offscreen bitmap has been purged */
  99. Boolean OffscreenPurged(OffscreenHandle offscreen)
  100. {
  101.     require(OffscreenValid(offscreen));
  102.     return(! *(**offscreen).base);
  103. }
  104.  
  105. /* true if currently drawing into the offscreen bitmap */
  106. Boolean OffscreenDrawing(OffscreenHandle offscreen)
  107. {
  108.     require(OffscreenValid(offscreen));
  109.     return((**offscreen).drawing);
  110. }
  111.  
  112. /* return the offscreen bitmap's port */
  113. GrafPtr OffscreenPort(OffscreenHandle offscreen)
  114. {
  115.     require(OffscreenValid(offscreen));
  116.     return((**offscreen).port);
  117. }
  118.  
  119. /* lock the handle to the base address of the offscreen bitmap */
  120. static void OffscreenLockBase(OffscreenHandle offscreen)
  121. {
  122.     (void) HandleLock((**offscreen).base);
  123.     (**offscreen).srcbits.baseAddr = *(**offscreen).base;
  124. }
  125.  
  126. /* unlock the handle to the base address of the offscreen bitmap */
  127. static void OffscreenUnlockBase(OffscreenHandle offscreen)
  128. {
  129.     HandleUnlock((**offscreen).base);
  130.     (**offscreen).srcbits.baseAddr = NULL;
  131. }
  132.  
  133. /* lock the handle to the offscreen structure */
  134. static void OffscreenLock(OffscreenHandle offscreen)
  135. {
  136.     (void) HandleLock(offscreen);
  137. }
  138.  
  139. /* unlock the handle to the offscreen structure */
  140. static void OffscreenUnlock(OffscreenHandle offscreen)
  141. {
  142.     HandleUnlock(offscreen);
  143. }
  144.  
  145. /* draw the offscreen bitmap into the port */
  146. void OffscreenDrawBitMap(OffscreenHandle offscreen)
  147. {
  148.     require(OffscreenValid(offscreen));
  149.     require(! OffscreenPurged(offscreen));
  150.     require(! (**offscreen).drawing);
  151.  
  152.     /* calculate mask region */
  153.     CopyRgn((**offscreen).port->clipRgn, (**offscreen).mask);
  154.     SectRgn((**offscreen).port->visRgn, (**offscreen).mask, (**offscreen).mask);
  155.  
  156.     /* copy destination bits bounds rect in case port was moved */
  157.     (**offscreen).dstbits = (**offscreen).port->portBits;
  158.     
  159.     /* draw the bit map */
  160.     OffscreenLock(offscreen);
  161.     OffscreenLockBase(offscreen);
  162.     CopyBits(&(**offscreen).srcbits,
  163.                 &(**offscreen).dstbits,
  164.                 &(**offscreen).bounds,
  165.                 &(**offscreen).bounds,
  166.                 srcCopy, (**offscreen).mask);
  167.     OffscreenUnlockBase(offscreen);
  168.     OffscreenUnlock(offscreen);
  169.     SetEmptyRgn((**offscreen).mask);
  170.  
  171.     ensure(OffscreenValid(offscreen));
  172. }
  173.  
  174. /* call the application supplied draw procedure to draw the image, whether
  175.     to the offscreen bitmap or to the on-screen bitmap */
  176. void OffscreenDrawProcedure(OffscreenHandle offscreen)
  177. {
  178.     require(OffscreenValid(offscreen));
  179.     (**offscreen).draw(offscreen, (**offscreen).data);
  180. }
  181.  
  182. /* If the offscreen bitmap's image has changed or if the bitmap was purged,
  183.     then reimage the bitmap and then draw the bitmap to the screen. If there's
  184.     insufficient memory to allocate the bitmap then just draw to the screen. */
  185. void OffscreenDraw(OffscreenHandle offscreen)
  186. {
  187.     volatile Boolean failed = false;
  188.     
  189.     require(OffscreenValid(offscreen));
  190.     TRY {
  191.         if (! failed) {
  192.             if ((**offscreen).changed || OffscreenPurged(offscreen)) {
  193.                 OffscreenBeginDrawing(offscreen);
  194.                 OffscreenDrawProcedure(offscreen);
  195.                 OffscreenEndDrawing(offscreen);
  196.                 (**offscreen).changed = false;
  197.             }
  198.             OffscreenDrawBitMap(offscreen);
  199.         }
  200.         else
  201.             OffscreenDrawProcedure(offscreen);
  202.     } CATCH {
  203.         if (OffscreenDrawing(offscreen))
  204.             OffscreenEndDrawing(offscreen);
  205.         if (! failed && FailReason() == memFullErr) {
  206.             failed = true;
  207.             RETRY;
  208.         }
  209.     } ENDTRY;
  210.     ensure(OffscreenValid(offscreen));
  211. }
  212.  
  213. /* Reassign the offscreen fields and reallocate the base address
  214.     for the offscreen bitmap if it was purged or if its size changed.
  215.     This must be called before beginning to draw the offscreen bitmap. */
  216. static void OffscreenReallocate(OffscreenHandle offscreen)
  217. {
  218.     size_t n = 0;
  219.     Rect bounds;
  220.     
  221.     require(OffscreenValid(offscreen));
  222.     require(! (**offscreen).drawing);
  223.     require(! (**offscreen).srcbits.baseAddr);
  224.     bounds = (**offscreen).bounds;
  225.     (**offscreen).dstbits = (**offscreen).port->portBits;
  226.     (**offscreen).srcbits.bounds = bounds;
  227.     (**offscreen).srcbits.rowBytes = ((RectWidth(&bounds) + 15) / 16) * 2;
  228.     n = RectHeight(&bounds) * (**offscreen).srcbits.rowBytes;
  229.     if (n != GetHandleSize((**offscreen).base)) {
  230.         EmptyHandle((**offscreen).base);
  231.         FailMemError();
  232.     }
  233.     if (! *(**offscreen).base) {
  234.         MemCheck(n);
  235.         ReallocateHandle((**offscreen).base, n);
  236.         FailMemError();
  237.         (void) HandlePurge((**offscreen).base);
  238.     }
  239.     ensure(! OffscreenPurged(offscreen));
  240. }
  241.  
  242. /* Initialize the offscreen's port so that all subsequent drawing into
  243.     it will go to the offscreen bitmap. The clip and visible regions
  244.     are set to the maximum size. This function must be balanced with a
  245.     call to OffscreenEndDrawing. Between the two calls, the size,
  246.     position, and visibility of the port should not be changed. */
  247. void OffscreenBeginDrawing(OffscreenHandle offscreen)
  248. {
  249.     Rect wide = { SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX };
  250.     GrafPtr port = NULL;
  251.     
  252.     require(OffscreenValid(offscreen));
  253.     require(! (**offscreen).drawing);
  254.     OffscreenReallocate(offscreen);
  255.     OffscreenLockBase(offscreen);
  256.     OffscreenLock(offscreen);
  257.     GetPort(&port);
  258.     SetPort((**offscreen).port);
  259.     CopyRgn((**offscreen).port->clipRgn, (**offscreen).clip);
  260.     CopyRgn((**offscreen).port->visRgn, (**offscreen).vis);
  261.     RectRgn((**offscreen).port->clipRgn, &wide);
  262.     RectRgn((**offscreen).port->visRgn, &wide);
  263.     SetPortBits(&(**offscreen).srcbits);
  264.     SetPort(port);
  265.     OffscreenUnlock(offscreen);
  266.     (**offscreen).drawing = true;
  267.     ensure(OffscreenValid(offscreen));
  268.     ensure((**offscreen).drawing);
  269. }
  270.  
  271. /* Restore the offscreen port's bitmap to its original setting. */
  272. void OffscreenEndDrawing(OffscreenHandle offscreen)
  273. {
  274.     GrafPtr port = NULL;
  275.     
  276.     require(OffscreenValid(offscreen));
  277.     require((**offscreen).drawing);
  278.     OffscreenUnlockBase(offscreen);
  279.     OffscreenLock(offscreen);
  280.     GetPort(&port);
  281.     SetPort((**offscreen).port);
  282.     CopyRgn((**offscreen).clip, (**offscreen).port->clipRgn);
  283.     CopyRgn((**offscreen).vis, (**offscreen).port->visRgn);
  284.     SetEmptyRgn((**offscreen).clip);
  285.     SetEmptyRgn((**offscreen).vis);
  286.     SetPortBits(&(**offscreen).dstbits);
  287.     SetPort(port);
  288.     OffscreenUnlock(offscreen);
  289.     (**offscreen).drawing = false;
  290.     ensure(OffscreenValid(offscreen));
  291.     ensure(! (**offscreen).drawing);
  292. }
  293.